from core.db import db
from datetime import datetime
from markdown import markdown
from core.exception import NotFoundException, AuthFailedException
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from vendor import login_manager


class Base(db.Model):
    __abstract__ = True
    create_time = db.Column(db.DateTime, index=True, default=datetime.now)
    status = db.Column(db.SmallInteger, default=1)  # 1为启用，0为删除

    def __getitem__(self, item):
        return getattr(self, item)

    # @property
    # def create_datetime(self):
    #     if self.create_time:
    #         return datetime.fromtimestamp(self.create_time)
    #     else:
    #         return None

    def set_attrs(self, attrs_dict):
        for key, value in attrs_dict.items():
            if hasattr(self, key) and key != 'id':
                setattr(self, key, value)

    def delete(self):
        self.status = 0

    def keys(self):
        return self.fields

    def hide(self, *keys):
        for key in keys:
            self.fields.remove(key)
        return self

    def append(self, *keys):
        for key in keys:
            self.fields.append(key)
        return self


# 前台用户表
class User(Base):
    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(24), unique=True)
    _password = db.Column('password', db.String(100))
    email = db.Column(db.String(24), unique=True, nullable=False)
    phone = db.Column(db.String(11), unique=True)
    info = db.Column(db.Text())
    avatar = db.Column(db.String(25), unique=True)
    uuid = db.Column(db.String(255), unique=True)
    auth = db.Column(db.SmallInteger, default=1)
    comment = db.relationship('Comment', backref='user')
    collect = db.relationship('Collect', backref='user')

    # 返回str字符串, 通过user来做标识
    def get_id(self):
        return 'user.'+str(self.id)

    def __repr__(self):
        return '<User %r>' % self.nickname

    def keys(self):
        return ['id', 'email', 'nickname', 'auth']

    def __getitem__(self, item):
        return getattr(self, item)

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, raw):
        self._password = generate_password_hash(raw)

    @staticmethod
    def register_by_email(nickname, account, secret):
        with db.auto_commit():
            user = User()
            user.nickname = nickname
            user.email = account
            user.password = secret
            db.session.add(user)

    @staticmethod
    def verify(email, password):
        user = User.query.filter_by(email=email).first()
        if not user:
            raise NotFoundException(msg='user not found')
        if not user.check_password(password):
            raise AuthFailedException()
        return {'uid': user.id}

    def check_password(self, raw):
        if not self._password:
            return False
        return check_password_hash(self._password, raw)


# 文章分类
class Category(Base):
    __tablename__ = "category"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    posts = db.relationship('Post', backref='category', lazy='dynamic')

    def __repr__(self):
        return "<Category %r>" % self.name


# 文章表
class Post(Base):
    __tablename__ = "post"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(255), unique=True)
    cover = db.Column(db.String(255))
    desc = db.Column(db.String(255))
    body = db.Column(db.Text)
    top = db.Column(db.Integer, default=0)
    category_id = db.Column(db.Integer, db.ForeignKey('category.id'))
    comment = db.relationship('Comment', backref='post')
    collect = db.relationship('Collect', backref='post')

    def __repr__(self):
        return "<Post %r>" % self.title

    def content_to_html(self):
        return markdown(self.content, extensions=[
            'markdown.extensions.extra',
            'markdown.extensions.codehilite',
        ])


# 文章评论
class Comment(Base):
    __tablename__ = 'comment'
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
    reply = db.relationship('Reply', backref='reply')

    def __repr__(self):
        return "<Comment %r>" % self.id


# 评论回复
class Reply(Base):
    __tablename__ = 'reply'
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    comment_id = db.Column(db.Integer, db.ForeignKey('comment.id'))

    def __repr__(self):
        return "<Comment %r>" % self.id


# 文章收藏
class Collect(Base):
    __tablename__ = 'collect'
    id = db.Column(db.Integer, primary_key=True)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return "<Collect %r>" % self.id


# 权限路由
class Auth(Base):
    __tablename__ = 'auth'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True)
    url = db.Column(db.String(255), unique=True)

    def __repr__(self):
        return "<Auth %r>" % self.name


# 角色
class Role(Base):
    __tablename__ = 'role'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), unique=True)
    auths = db.Column(db.String(600))
    admin = db.relationship('Admin', backref='role')

    def __repr__(self):
        return "<Role %r>" % self.name


# 管理员
class Admin(Base, UserMixin):
    __tablename__ = 'admin'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(100), unique=True)
    password = db.Column(db.String(100))
    is_super = db.Column(db.SmallInteger, default=1)  # 1是超级管理员
    role_id = db.Column(db.Integer, db.ForeignKey('role.id'))

    def __repr__(self):
        return "<Admin %r>" % self.name

    def check_admin_password(self, raw):
        return check_password_hash(self.password, raw)

    # 使用flask-login的UserMixin或者自己实现UserMixin中的方法,我这里使用了前者
    # def is_authenticated(self):
    #     return True
    #
    # def is_active(self):
    #     return True
    #
    # def is_anonymous(self):
    #     return False
    #

    # 返回str字符串, 通过admin来做标识
    def get_id(self):
        return 'admin.'+str(self.id)


@login_manager.user_loader
def load_user(user_id):
    print(user_id)
    temp = user_id.split('.')
    try:
        uid = temp[1]
        if temp[0] == 'admin':
            print("admin...")
            return Admin.query.get(uid)
        elif temp[0] == 'user':
            print("user...")
            return User.query.get(uid)
        else:
            return None
    except IndexError:
        return None
